home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / smaltalk / manchest.lha / MANCHESTER / manchester / 2.2 / Parallelism.st < prev    next >
Text File  |  1993-07-24  |  49KB  |  1,588 lines

  1. "    NAME        Parallelism
  2.     AUTHOR        tph@cs.man.ac.uk
  3.     FUNCTION throttled Futures; lazy eval; explicit pa'l'l procs 
  4.     ST-VERSIONS    2.2
  5.     PREREQUISITES     
  6.     CONFLICTS    
  7.     DISTRIBUTION      world
  8.     VERSION        1.1
  9.     DATE    22 Jan 1989
  10. SUMMARY    Parallelism
  11.     contains a number of explicitly parallel constructs,
  12.    including a new version of Future, Lazy evaluation, and explicit
  13.    parallel processes.  Lots of code in here.  Contains an early
  14.    version (read: doesn't work) of a ""throttled"" future mechanism.
  15.    New version RSN.(2.2).TPH
  16. "!
  17. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:13:27 pm'!
  18.  
  19.  
  20.  
  21. !Object methodsFor: 'parallel evaluation'!
  22.  
  23. touch
  24.     "Simply returns self.  If the receiver is an uncompleted
  25.      Future or Lazy, this forces complete evaluation."
  26.  
  27.     ^self! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:03:50 pm'!
  28.  
  29.  
  30.  
  31. !Array methodsFor: 'products'!
  32.  
  33. dotProduct: anArray
  34.     "Answers with the sum of the products of each element
  35.      of the receiver with anArray.  Creates an error if the
  36.      receiver and anArray are different sizes."
  37.  
  38.     (self size = anArray size) ifFalse: [^self error: 'arrays must be the same size'].
  39.     ^self fastDotProduct: anArray!
  40.  
  41. fastDotProduct: anArray 
  42.     "Answers with the sum of the products of each element 
  43.      of the receiver with anArray."
  44.  
  45.     | sum |
  46.     sum _ 0.
  47.     1 to: self size do: [:index |
  48.         sum _ sum + ((self at: index) * (anArray at: index))].
  49.     ^sum! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:19:19 pm'!
  50.  
  51.  
  52.  
  53. !Semaphore class methodsFor: 'instance creation'!
  54.  
  55. new: aNumber
  56.     "Answer a new instance of Semaphore that contains aNumber signals.
  57.      This is used by ThrottedFutures."
  58.  
  59.     ^self basicNew excessSignals: aNumber! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:19:30 pm'!
  60.  
  61.  
  62.  
  63. !Semaphore methodsFor: 'private'!
  64.  
  65. excessSignals: aNumber
  66.     "Set the number of excessSignals to aNumber."
  67.  
  68.     excessSignals _ aNumber! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:08:06 pm'!
  69.  
  70. Object subclass: #Future
  71.     instanceVariableNames: 'result semaphore '
  72.     classVariableNames: ''
  73.     poolDictionaries: ''
  74.     category: 'Kernel-Processes'!
  75. Future comment:
  76. 'I represent an execution in progress.  Any messages sent to me are delayed until execution has completed.'!
  77.  
  78.  
  79. !Future methodsFor: 'synchronising'!
  80.  
  81. doesNotUnderstand: aMessage
  82.     "Any message to a Future will end up here."
  83.  
  84.     semaphore wait.    "Wait for evaluation to complete"
  85.                         "(if not already completed)"
  86.     semaphore signal.    "Wake up anything else that might be waiting"
  87.     ^result perform: aMessage selector withArguments: aMessage arguments! !
  88.  
  89. !Future methodsFor: 'evaluating'!
  90.  
  91. block: aBlock
  92.     "Execute aBlock in parallel with whatever called me, but
  93.      ensure that any messages sent to me before execution
  94.      of the block has terminated are suspended until it has terminated."
  95.  
  96.     semaphore _ Semaphore new.
  97.     [result _ aBlock value.  semaphore signal] fork!
  98.  
  99. block: aBlock value: aValue
  100.     "Execute aBlock in parallel with whatever called me, but
  101.      ensure that any messages sent to me before execution
  102.      of the block has terminated are suspended until it has terminated."
  103.  
  104.     semaphore _ Semaphore new.
  105.     [result _ aBlock value: aValue.  semaphore signal] fork!
  106.  
  107. block: aBlock value: value1 value: value2
  108.     "Execute aBlock in parallel with whatever called me, but
  109.      ensure that any messages sent to me before execution
  110.      of the block has terminated are suspended until it has terminated."
  111.  
  112.     semaphore _ Semaphore new.
  113.     [result _ aBlock value: value1 value: value2.
  114.      semaphore signal] fork!
  115.  
  116. block: aBlock value: value1 value: value2 value: value3
  117.     "Execute aBlock in parallel with whatever called me, but
  118.      ensure that any messages sent to me before execution
  119.      of the block has terminated are suspended until it has terminated."
  120.  
  121.     semaphore _ Semaphore new.
  122.     [result _ aBlock value: value1 value: value2 value: value3.
  123.      semaphore signal] fork!
  124.  
  125. block: aBlock valueWithArguments: anArray
  126.     "Execute aBlock in parallel with whatever called me, but
  127.      ensure that any messages sent to me before execution
  128.      of the block has terminated are suspended until it has terminated."
  129.  
  130.     semaphore _ Semaphore new.
  131.     [result _ aBlock valueWithArguments: anArray.
  132.      semaphore signal] fork! !
  133. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  134.  
  135. Future class
  136.     instanceVariableNames: ''!
  137.  
  138.  
  139. !Future class methodsFor: 'examples'!
  140.  
  141. example1
  142.     "Starts evaluating the factorial immediately, but waits until
  143.      the result is available before printing the answer!!"
  144.  
  145.     | fac |
  146.     fac _ [100 factorial] futureValue.
  147.     Transcript show: 'evaluating factorial...'.
  148.     Transcript show: fac printString
  149.  
  150.     "Future example1"!
  151.  
  152. example2
  153.     "An example illustrating the use of multiple futures and
  154.      explicit resynchronisation."
  155.  
  156.     "Starts evaluating both factorials immediately, but waits until
  157.      both blocks have finished before continuing."
  158.  
  159.     | fac1 fac2 |
  160.     fac1 _ [Transcript show: 'Starting fac1.. '. 100 factorial] futureValue.
  161.     fac2 _ [Transcript show: 'Starting fac2.. '. 120 factorial] futureValue.
  162.     fac2 touch.
  163.     fac1 touch.
  164.     Transcript show: 'both completed.'.
  165.  
  166.     "Future example2"!
  167.  
  168. example3
  169.     "Example showing how arguments may be passed to futures."
  170.  
  171.     | temp |
  172.     temp _ [:x :y | 10 * x * y] futureValue: 3 value: 4.
  173.     Transcript cr; show: temp printString.
  174.  
  175.     "Future example3"! !
  176.  
  177. !Future class methodsFor: 'class initialization'!
  178.  
  179. initialize
  180.      "must avoid the checks"
  181.  
  182.     superclass _ nil
  183.  
  184.     "Future initialize."! !
  185.  
  186. Future initialize!
  187. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:09:10 pm'!
  188.  
  189. Object subclass: #Lazy
  190.     instanceVariableNames: 'result startSemaphore endSemaphore '
  191.     classVariableNames: ''
  192.     poolDictionaries: ''
  193.     category: 'Kernel-Processes'!
  194. Lazy comment:
  195. 'I represent an execution which may not be required.  I will
  196. not start execution until at least one message has been
  197. received.  The messages sent to me are delayed until execution
  198. has completed.'!
  199.  
  200.  
  201. !Lazy methodsFor: 'synchronising'!
  202.  
  203. doesNotUnderstand: aMessage
  204.     "Any message to a Lazy will end up here."
  205.  
  206.     startSemaphore signal.        "Start the evaluation."
  207.     endSemaphore wait.        "Wait until evaluation completed."
  208.     endSemaphore signal.        "Wake up anything else."
  209.     ^result perform: aMessage selector withArguments: aMessage arguments
  210.         "Perform the message, having re-synchronised."! !
  211.  
  212. !Lazy methodsFor: 'evaluating'!
  213.  
  214. block: aBlock
  215.     "Execute aBlock in parallel, but ensure that any messages sent
  216.      to me before execution of the block has terminated are
  217.      suspended until it has terminated. Do not start the evaluation
  218.      until at least one message has been sent to the receiver."
  219.  
  220.     startSemaphore _ Semaphore new.
  221.     endSemaphore _ Semaphore new.
  222.     [startSemaphore wait.
  223.      result _ aBlock value.
  224.      endSemaphore signal] fork!
  225.  
  226. block: aBlock value: aValue
  227.     "Execute aBlock in parallel, but ensure that any messages sent
  228.      to me before execution of the block has terminated are
  229.      suspended until it has terminated. Do not start the evaluation
  230.      until at least one message has been sent to the receiver."
  231.  
  232.     startSemaphore _ Semaphore new.
  233.     endSemaphore _ Semaphore new.
  234.     [startSemaphore wait.
  235.      result _ aBlock value: aValue.
  236.      endSemaphore signal] fork!
  237.  
  238. block: aBlock value: value1 value: value2
  239.     "Execute aBlock in parallel, but ensure that any messages sent
  240.      to me before execution of the block has terminated are
  241.      suspended until it has terminated. Do not start the evaluation
  242.      until at least one message has been sent to the receiver."
  243.  
  244.     startSemaphore _ Semaphore new.
  245.     endSemaphore _ Semaphore new.
  246.     [startSemaphore wait.
  247.      result _ aBlock value: value1 value: value2.
  248.      endSemaphore signal] fork!
  249.  
  250. block: aBlock value: value1 value: value2 value: value3
  251.     "Execute aBlock in parallel, but ensure that any messages sent
  252.      to me before execution of the block has terminated are
  253.      suspended until it has terminated. Do not start the evaluation
  254.      until at least one message has been sent to the receiver."
  255.  
  256.     startSemaphore _ Semaphore new.
  257.     endSemaphore _ Semaphore new.
  258.     [startSemaphore wait.
  259.      result _ aBlock value: value1 value: value2 value: value3.
  260.      endSemaphore signal] fork!
  261.  
  262. block: aBlock valueWithArguments: anArray
  263.     "Execute aBlock in parallel, but ensure that any messages sent
  264.      to me before execution of the block has terminated are
  265.      suspended until it has terminated. Do not start the evaluation
  266.      until at least one message has been sent to the receiver."
  267.  
  268.     startSemaphore _ Semaphore new.
  269.     endSemaphore _ Semaphore new.
  270.     [startSemaphore wait.
  271.      result _ aBlock valueWithArguments: anArray.
  272.      endSemaphore signal] fork! !
  273. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  274.  
  275. Lazy class
  276.     instanceVariableNames: ''!
  277.  
  278.  
  279. !Lazy class methodsFor: 'class initialization'!
  280.  
  281. initialize
  282.      "must avoid the checks"
  283.  
  284.     superclass _ nil
  285.  
  286.     "Lazy initialize."! !
  287.  
  288. !Lazy class methodsFor: 'examples'!
  289.  
  290. example1
  291.     "Evaluates the factorial, starting only when the
  292.      result is actually required (when printString is sent)."
  293.  
  294.     | fac |
  295.     fac _ [100 factorial] futureValue.
  296.     Transcript show: 'Doing nothing. '.
  297.     (Delay forSeconds: 2) wait.
  298.     Transcript show: fac printString
  299.  
  300.     "Lazy example1"!
  301.  
  302. example2
  303.     "Starts evaluating both factorials only when required (by the touch),
  304.      and waits until both blocks have finished before continuing."
  305.  
  306.     | fac1 fac2 |
  307.     fac1 _ [Transcript show: 'Starting fac1.. '. 100 factorial] lazyValue.
  308.     fac2 _ [Transcript show: 'Starting fac2.. '. 120 factorial] lazyValue.
  309.     fac2 touch.
  310.     fac1 touch.
  311.     Transcript show: 'both completed.'.
  312.  
  313.     "Lazy example2"!
  314.  
  315. example3
  316.     "Demonstrates how to pass arguments to a lazy evaluation block."
  317.  
  318.     | temp |
  319.     temp _ [:x :y :z | x * y * z] lazyValueWithArguments: #(2 3 4).
  320.     Transcript cr; show: temp printString.
  321.  
  322.     "Lazy example3"! !
  323.  
  324. Lazy initialize!
  325. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:44:46 pm'!
  326.  
  327. Future subclass: #ThrottledFuture
  328.     instanceVariableNames: ''
  329.     classVariableNames: 'ThrottleSemaphore '
  330.     poolDictionaries: ''
  331.     category: 'Kernel-Processes'!
  332. ThrottledFuture comment:
  333. 'I represent an execution in progress.  Any messages sent to me
  334. are delayed until execution has completed.  I am different from
  335. Future, in that I will only spawn a limited number of processes,
  336. up to the limit given in the class initialization method.  The limit
  337. is enforced a signal/wait mechanism, using the class variable
  338. <ThrottleSemaphore>.
  339. '!
  340.  
  341.  
  342. !ThrottledFuture methodsFor: 'evaluating'!
  343.  
  344. block: aBlock
  345.     "Execute aBlock in parallel, and resynchronise after
  346.      completion.  Do not start the evaluation if too many
  347.      futures are already executing."
  348.  
  349.     ThrottledFuture throttle wait.        "Wait for process available."
  350.     super block: aBlock.                    "Start the future."!
  351.  
  352. block: aBlock value: aValue
  353.     "Execute aBlock in parallel, and resynchronise after
  354.      completion.  Do not start the evaluation if too many
  355.      futures are already executing."
  356.  
  357.     ThrottledFuture throttle wait.        "Wait for process available."
  358.     super block: aBlock value: aValue.    "Start the future."!
  359.  
  360. block: aBlock value: value1 value: value2
  361.     "Execute aBlock in parallel, and resynchronise after
  362.      completion.  Do not start the evaluation if too many
  363.      futures are already executing."
  364.  
  365.     ThrottledFuture throttle wait.        "Wait for process available."
  366.     super block: aBlock value: value1 value: value2.!
  367.  
  368. block: aBlock value: value1 value: value2 value: value3
  369.     "Execute aBlock in parallel, and resynchronise after
  370.      completion.  Do not start the evaluation if too many
  371.      futures are already executing."
  372.  
  373.     ThrottledFuture throttle wait.        "Wait for process available."
  374.     super block: aBlock value: value1 value: value2 value: value3.!
  375.  
  376. block: aBlock valueWithArguments: anArray
  377.     "Execute aBlock in parallel, and resynchronise after
  378.      completion.  Do not start the evaluation if too many
  379.      futures are already executing."
  380.  
  381.     ThrottledFuture throttle wait.        "Wait for process available."
  382.     super block: aBlock valueWithArguments: anArray.! !
  383.  
  384. !ThrottledFuture methodsFor: 'synchronising'!
  385.  
  386. doesNotUnderstand: aMessage
  387.     "Any message to a ThrottledFuture will end up here."
  388.  
  389.     semaphore wait.    "Wait for evaluation to complete"
  390.                         "(if not already completed)"
  391.     semaphore signal.    "Wake up anything else that might be waiting"
  392.     ThrottledFuture throttle signal.  "Signal end of execution."
  393.     ^result perform: aMessage selector withArguments: aMessage arguments! !
  394. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  395.  
  396. ThrottledFuture class
  397.     instanceVariableNames: ''!
  398.  
  399.  
  400. !ThrottledFuture class methodsFor: 'class initialization'!
  401.  
  402. initialize
  403.     "Maximum number of ThrottledFutures created."
  404.  
  405.     ThrottleSemaphore _ Semaphore new: 4
  406.  
  407.     "ThrottledFuture initialize."! !
  408.  
  409. !ThrottledFuture class methodsFor: 'class access'!
  410.  
  411. throttle
  412.     "Answer the throttle semaphore."
  413.  
  414.     ^ThrottleSemaphore! !
  415.  
  416. ThrottledFuture initialize!
  417. 'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:14:17 pm'!
  418.  
  419. Object subclass: #ParallelEvaluation
  420.     instanceVariableNames: 'futures '
  421.     classVariableNames: ''
  422.     poolDictionaries: ''
  423.     category: 'Kernel-Processes'!
  424. ParallelEvaluation comment:
  425. 'I represent a collection of explicitly parallel computations.  All of the computations are completed before I return.
  426. '!
  427.  
  428.  
  429. !ParallelEvaluation methodsFor: 'private'!
  430.  
  431. initialize
  432.     "Create a new OrderedCollection of futures."
  433.  
  434.     futures _ OrderedCollection new.! !
  435.  
  436. !ParallelEvaluation methodsFor: 'synchronisation'!
  437.  
  438. do
  439.     "Evaluates all futures in parallel, forcing resynchronisation."
  440.  
  441.     futures isEmpty ifTrue: [^nil].
  442.     futures do: [:each | each touch]! !
  443.  
  444. !ParallelEvaluation methodsFor: 'adding'!
  445.  
  446. add: aBlock
  447.     "Add aBlock to the collection of futures to be evaluated in parallel."
  448.  
  449.     futures addLast: (Future new block: aBlock)!
  450.  
  451. add: aBlock value: aValue
  452.     "Add aBlock to the collection of futures to be evaluated in parallel."
  453.  
  454.     futures addLast: (Future new block: aBlock value: aValue)!
  455.  
  456. add: aBlock value: aValue value: anotherValue
  457.     "Add aBlock to the collection of futures to be evaluated in parallel."
  458.  
  459.     futures addLast: (Future new block: aBlock value: aValue value: anotherValue)!
  460.  
  461. add: aBlock value: aValue value: anotherValue value: bValue
  462.     "Add aBlock to the collection of futures to be evaluated in parallel."
  463.  
  464.     futures addLast:
  465.      (Future new block: aBlock value: aValue value: anotherValue value: bValue)!
  466.  
  467. add: aBlock withArguments: anArray
  468.     "Add aBlock to the collection of futures to be evaluated in parallel."
  469.  
  470.     futures addLast: (Future new block: aBlock valueWithArguments: anArray)! !
  471. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  472.  
  473. ParallelEvaluation class
  474.     instanceVariableNames: ''!
  475.  
  476.  
  477. !ParallelEvaluation class methodsFor: 'instance creation'!
  478.  
  479. new
  480.  
  481.     ^super new initialize! !
  482.  
  483. !ParallelEvaluation class methodsFor: 'examples'!
  484.  
  485. example1
  486.     "An example of using a parallel evaluation. "
  487.  
  488.     | t |
  489.     t _ ParallelEvaluation new.
  490.     t add: [Transcript cr; show: 'First block. '].
  491.     t add: [(Delay forSeconds: 5) wait. Transcript cr; show: 'Second block. '].
  492.     t add: [Transcript cr; show: 'Third block. '].
  493.     t add: [(Delay forSeconds: 2) wait. Transcript cr; show: 'Forth block. '].
  494.     t add: [Transcript cr; show: 'Fifth block. '].
  495.     t do.
  496.     Transcript cr; show: 'All blocks finished. '.
  497.  
  498.     "ParallelEvaluation example1."!
  499.  
  500. example2
  501.     "Uses the BlockContext method."
  502.  
  503.     [(Delay forSeconds: 2) wait. Transcript cr; show: 'First Block. ']
  504.         inParallelWith: [Transcript cr; show: 'Second Block. '].
  505.     Transcript cr; show: 'Both blocks finished.'
  506.  
  507.     "ParallelEvaluation example2."!
  508.  
  509. example3
  510.     "Also uses the BlockContext method."
  511.  
  512.     [Transcript cr; show: 'First Block. ']
  513.         inParallelWith: [Transcript cr; show: 'Second Block. ']
  514.         with: [Transcript cr; show: 'Third Block. '].
  515.     Transcript cr; show: 'All completed. '
  516.  
  517.     "ParallelEvaluation example3."!
  518.  
  519. example4
  520.     "Example showing how to pass arguments to blocks
  521.      which are to be evaluated in parallel."
  522.  
  523.     [:x | Transcript cr; show: x printString] value: 10
  524.         inParallelWith: [:y | Transcript cr; show: (2 * y) printString] value: 3.
  525.  
  526.     "ParallelEvaluation example4."!
  527.  
  528. sortExample
  529.     "Uses a parallel in-place Quicksort algorithm to sort collections.
  530.      Note that on a single processor, this is somewhat slower
  531.      than the single-process version!!"
  532.  
  533.     Transcript show: (
  534.     #(5 4 4 3 2 2 1 6 5 6 8 7 6 6 4 5 6 7 6 5 4 3
  535.        2 1 2 3 4 5 6 7 8 9 0 9 8 7 6 5 4 3 2 1 2 3
  536.        4 5 6 7 8 9 0 9 8 7 6 5 4 3 2 1 1 2 4 6 6 6)
  537.             asParallelSortedCollection) printString.
  538.  
  539.     "ParallelEvaluation sortExample."!
  540.  
  541. sortExample2
  542.     "Uses a parallel in-place Quicksort algorithm to sort dictionaries.
  543.      Note that on a single processor, this is somewhat slower
  544.      than the single-process version!!"
  545.  
  546.     Transcript cr; show: (
  547.         Time millisecondsToRun: [Smalltalk asSortedCollection]) printString.
  548.     Transcript cr; show: (
  549.         Time millisecondsToRun: [Smalltalk asParallelSortedCollection]) printString.
  550.  
  551.     "ParallelEvaluation sortExample2."! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:04:08 pm'!
  552.  
  553.  
  554.  
  555. !BlockContext methodsFor: 'parallel evaluation'!
  556.  
  557. futureValue
  558.     "Fork a synchronised evaluation of myself. Starts the
  559.      evaluation in parallel immediately."
  560.  
  561.     ^Future new block: self!
  562.  
  563. futureValue: aValue
  564.     "Fork a synchronised evaluation of myself. Starts the
  565.      evaluation in parallel immediately."
  566.  
  567.     ^Future new block: self value: aValue!
  568.  
  569. futureValue: aValue value: anotherValue
  570.     "Fork a synchronised evaluation of myself. Starts the
  571.      evaluation in parallel immediately."
  572.  
  573.     ^Future new block: self value: aValue value: anotherValue!
  574.  
  575. futureValue: aValue value: anotherValue value: bValue
  576.     "Fork a synchronised evaluation of myself. Starts the
  577.      evaluation in parallel immediately."
  578.  
  579.     ^Future new block: self value: aValue value: anotherValue value: bValue!
  580.  
  581. futureValueWithArguments: anArray
  582.     "Fork a synchronised evaluation of myself. Starts the
  583.      evaluation in parallel immediately."
  584.  
  585.     ^Future new block: self valueWithArguments: anArray!
  586.  
  587. inParallelWith: aBlock
  588.     "Executes the receiver in parallel with aBlock. Continue
  589.      only after both have completed."
  590.  
  591.     | aParallelEvaluation |
  592.     aParallelEvaluation _ ParallelEvaluation new add: self.
  593.     aParallelEvaluation add: aBlock.
  594.     aParallelEvaluation do!
  595.  
  596. inParallelWith: aBlock value: aValue
  597.     "Executes the receiver in parallel with aBlock. Continue
  598.      only after both have completed."
  599.  
  600.     | aParallelEvaluation |
  601.     aParallelEvaluation _ ParallelEvaluation new add: self.
  602.     aParallelEvaluation add: aBlock value: aValue.
  603.     aParallelEvaluation do!
  604.  
  605. inParallelWith: aBlock with: anotherBlock
  606.     "Executes the receiver in parallel with aBlock and anotherBlock.
  607.      Continue only after all have completed."
  608.  
  609.     | aParallelEvaluation |
  610.     aParallelEvaluation _ ParallelEvaluation new add: self.
  611.     aParallelEvaluation add: aBlock.
  612.     aParallelEvaluation add: anotherBlock.
  613.     aParallelEvaluation do!
  614.  
  615. lazyValue
  616.     "Fork a synchronised evaluation of myself. Only starts
  617.      the evaluation when the result is requested."
  618.  
  619.     ^Lazy new block: self!
  620.  
  621. lazyValue: aValue
  622.     "Fork a synchronised evaluation of myself. Only starts
  623.      the evaluation when the result is requested."
  624.  
  625.     ^Lazy new block: self value: aValue!
  626.  
  627. lazyValue: aValue value: anotherValue
  628.     "Fork a synchronised evaluation of myself. Only starts
  629.      the evaluation when the result is requested."
  630.  
  631.     ^Lazy new block: self value: aValue value: anotherValue!
  632.  
  633. lazyValue: aValue value: anotherValue value: bValue
  634.     "Fork a synchronised evaluation of myself. Only starts
  635.      the evaluation when the result is requested."
  636.  
  637.     ^Lazy new block: self value: aValue value: anotherValue value: bValue!
  638.  
  639. lazyValueWithArguments: anArray
  640.     "Fork a synchronised evaluation of myself. Only starts
  641.      the evaluation when the result is requested."
  642.  
  643.     ^Lazy new block: self valueWithArguments: anArray!
  644.  
  645. parallelAnd: aBlock 
  646.     "Executes the receiver in parallel with aBlock. Once both   
  647.      have completed, perform a logical AND operation."
  648.  
  649.     | first second |
  650.     first _ self futureValue.
  651.     second _ aBlock futureValue.
  652.     ^first touch & second touch!
  653.  
  654. parallelEqv: aBlock 
  655.     "Executes the receiver in parallel with aBlock. Once both   
  656.      have completed, perform a logical equivalence (exclusive-NOR)
  657.      operation."
  658.  
  659.     | first second |
  660.     first _ self futureValue.
  661.     second _ aBlock futureValue.
  662.     ^first touch eqv: second touch!
  663.  
  664. parallelOr: aBlock 
  665.     "Executes the receiver in parallel with aBlock. Once both   
  666.      have completed, perform a logical OR operation."
  667.  
  668.     | first second |
  669.     first _ self futureValue.
  670.     second _ aBlock futureValue.
  671.     ^first touch | second touch!
  672.  
  673. parallelPerform: aSymbol with: aBlock 
  674.     "Executes the receiver in parallel with aBlock. Once both  
  675.      have completed, perform the operation given by aSymbol."
  676.  
  677.     | first second |
  678.     first _ self futureValue.
  679.     second _ aBlock futureValue.
  680.     ^first touch perform: aSymbol with: second touch!
  681.  
  682. parallelXor: aBlock 
  683.     "Executes the receiver in parallel with aBlock. Once both   
  684.      have completed, perform a logical equivalence (exclusive-NOR)
  685.      operation."
  686.  
  687.     | first second |
  688.     first _ self futureValue.
  689.     second _ aBlock futureValue.
  690.     ^first touch xor: second touch!
  691.  
  692. throttledFutureValue
  693.     "Fork a synchronised evaluation of myself. Starts the
  694.      evaluation in parallel immediately only if less than the
  695.      maximum number of processes are already executing."
  696.  
  697.     ^ThrottledFuture new block: self!
  698.  
  699. throttledFutureValue: aValue
  700.     "Fork a synchronised evaluation of myself. Starts the
  701.      evaluation in parallel immediately only if less than the
  702.      maximum number of processes are already executing."
  703.  
  704.     ^ThrottledFuture new block: self value: aValue!
  705.  
  706. throttledFutureValue: aValue value: anotherValue
  707.     "Fork a synchronised evaluation of myself. Starts the
  708.      evaluation in parallel immediately only if a small number of
  709.      processes are already executing."
  710.  
  711.     ^ThrottledFuture new block: self value: aValue value: anotherValue!
  712.  
  713. throttledFutureValue: aValue value: anotherValue value: bValue
  714.     "Fork a synchronised evaluation of myself. Starts the
  715.      evaluation in parallel immediately only if a small number of
  716.      processes are already executing."
  717.  
  718.     ^ThrottledFuture new block: self value: aValue value: anotherValue value: bValue!
  719.  
  720. throttledParallelPerform: aSymbol with: aBlock 
  721.     "Executes the receiver in parallel with aBlock. Once both  
  722.      have completed, perform the operation given by aSymbol."
  723.  
  724.     | first second |
  725.     first _ self throttledFutureValue.
  726.     second _ aBlock throttledFutureValue.
  727.     ^first touch perform: aSymbol with: second touch!
  728.  
  729. throtttledFutureValueWithArguments: anArray
  730.     "Fork a synchronised evaluation of myself. Starts the
  731.      evaluation in parallel immediately only if a small
  732.      number of processes are already executing."
  733.  
  734.     ^ThrottledFuture new block: self valueWithArguments: anArray!
  735.  
  736. value: aValue inParallelWith: aBlock
  737.     "Executes the receiver in parallel with aBlock. Continue
  738.      only after both have completed."
  739.  
  740.     | aParallelEvaluation |
  741.     aParallelEvaluation _ ParallelEvaluation new add: self value: aValue.
  742.     aParallelEvaluation add: aBlock.
  743.     aParallelEvaluation do!
  744.  
  745. value: aValue inParallelWith: aBlock value: anotherValue
  746.     "Executes the receiver in parallel with aBlock. Continue
  747.      only after both have completed."
  748.  
  749.     | aParallelEvaluation |
  750.     aParallelEvaluation _ ParallelEvaluation new add: self value: aValue.
  751.     aParallelEvaluation add: aBlock value: anotherValue.
  752.     aParallelEvaluation do! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:19:49 pm'!
  753.  
  754.  
  755.  
  756. !SequenceableCollection methodsFor: 'parallel evaluation'!
  757.  
  758. parallelDo: aBlock 
  759.     "Perform the block aBlock with all elements of the
  760.      receiver in parallel, using a parallel evaluation mechanism."
  761.  
  762.     "Watch out for blocks with side-effects, as the blocks may
  763.      be executed in any order."
  764.  
  765.      | index length aPE |
  766.     aPE _ ParallelEvaluation new.
  767.     index _ 0.
  768.     length _ self size.
  769.     [(index _ index + 1) <= length]
  770.         whileTrue: [aPE add: aBlock value: (self at: index)].
  771.     aPE do        "ensure all blocks have terminated before continuing."! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:20:34 pm'!
  772.  
  773.  
  774.  
  775. !SortedCollection methodsFor: 'adding'!
  776.  
  777. parallelAdd: newObject 
  778.     "Don't actually force a sort, as we will always resort later."
  779.  
  780.     ^super addLast: newObject! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:20:36 pm'!
  781.  
  782.  
  783.  
  784. !SortedCollection methodsFor: 'adding'!
  785.  
  786. parallelAddAll: aCollection 
  787.     "Use the parallel sorting mechanism, so
  788.      always insert everything and resort."
  789.  
  790.     aCollection do: [:each | super addLast: each].
  791.     self parallelReSort! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:20:30 pm'!
  792.  
  793.  
  794.  
  795. !SortedCollection methodsFor: 'private'!
  796.  
  797. parallelReSort
  798.     self parallelSort: firstIndex to: lastIndex! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:20:26 pm'!
  799.  
  800.  
  801.  
  802. !SortedCollection methodsFor: 'private'!
  803.  
  804. parallelSort: i to: j 
  805.     "Sort elements i through j of self to be nondescending according to sortBlock.
  806.      Use the parallel evaluation mechanism to spawn off processes."
  807.  
  808.     | di dij dj tt ij k l n |
  809.     "The prefix d means the data at that index."
  810.     (n _ j + 1  - i) <= 1 ifTrue: [^self].    "Nothing to sort." 
  811.      "Sort di,dj."
  812.     di _ self basicAt: i.
  813.     dj _ self basicAt: j.
  814.     (sortBlock value: di value: dj) "i.e., should di precede dj?"
  815.         ifFalse: 
  816.             [self swap: i with: j.
  817.              tt _ di.
  818.              di _ dj.
  819.              dj _ tt].
  820.     n > 2
  821.         ifTrue:  "More than two elements."
  822.             [ij _ (i + j) // 2.  "ij is the midpoint of i and j."
  823.              dij _ self basicAt: ij.  "Sort di,dij,dj.  Make dij be their median."
  824.              (sortBlock value: di value: dij) "i.e. should di precede dij?"
  825.                ifTrue: 
  826.                 [(sortBlock value: dij value: dj) "i.e., should dij precede dj?"
  827.                   ifFalse: 
  828.                     [self swap: j with: ij.
  829.                      dij _ dj]]
  830.                ifFalse:  "i.e. di should come after dij"
  831.                 [self swap: i with: ij.
  832.                  dij _ di].
  833.             n > 3
  834.               ifTrue:  "More than three elements."
  835.                 ["Find k>i and l<j such that dk,dij,dl are in reverse order.
  836.                 Swap k and l.  Repeat this procedure until k and l pass each other."
  837.                  k _ i.
  838.                  l _ j.
  839.                  [[l _ l - 1.  k <= l and: [sortBlock value: dij value: (self basicAt: l)]]
  840.                    whileTrue.  "i.e. while dl succeeds dij"
  841.                   [k _ k + 1.  k <= l and: [sortBlock value: (self basicAt: k) value: dij]]
  842.                    whileTrue.  "i.e. while dij succeeds dk"
  843.                   k <= l]
  844.                    whileTrue:
  845.                     [self swap: k with: l]. 
  846.     "Now l<k (either 1 or 2 less), and di through dl are all less than or equal to dk
  847.     through dj.  Sort those two segments in parallel."
  848.                 [self parallelSort: i to: l] inParallelWith: [self parallelSort: k to: j]]]! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:07:32 pm'!
  849.  
  850.  
  851.  
  852. !Collection methodsFor: 'converting'!
  853.  
  854. asParallelSortedCollection
  855.     "Answer a new instance of SortedCollection whose elements are the elements of
  856.     the receiver.  The sort order is the default less than or equal ordering.
  857.      Use the parallel sorting mechanism."
  858.  
  859.     | aSortedCollection |
  860.     aSortedCollection _ SortedCollection new: self size.
  861.     aSortedCollection parallelAddAll: self.
  862.     ^aSortedCollection! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:07:27 pm'!
  863.  
  864.  
  865.  
  866. !Collection methodsFor: 'converting'!
  867.  
  868. asParallelSortedCollection: aBlock 
  869.     "Answer a new instance of SortedCollection whose elements are the elements of
  870.      the receiver.  The sort order is defined by the argument, aBlock.
  871.      Use the parallel sorting method."
  872.  
  873.     | aSortedCollection |
  874.     aSortedCollection _ SortedCollection new: self size.
  875.     aSortedCollection sortBlock: aBlock.
  876.     aSortedCollection parallelAddAll: self.
  877.     ^aSortedCollection! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:07:48 pm'!
  878.  
  879.  
  880.  
  881. !Dictionary methodsFor: 'converting'!
  882.  
  883. asParallelSortedCollection
  884.     | aSortedCollection |
  885.     aSortedCollection _ SortedCollection new: self size.
  886.     self associationsDo: [:association | aSortedCollection parallelAdd: association].
  887.     aSortedCollection parallelReSort.
  888.     ^aSortedCollection! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:08:56 pm'!
  889.  
  890.  
  891.  
  892. !Integer methodsFor: 'factorization and divisibility'!
  893.  
  894. factorial3
  895.     "Answer the factorial of the receiver.  For example,
  896.      6 factorial == 6*5*4*3*2*1. Signal an error if the receiver
  897.      is less than 0. Use explicitly parallel eager evaluation."
  898.  
  899.     self > 0
  900.         ifTrue: [^self * [(self - 1) factorial] futureValue].
  901.     self = 0
  902.         ifTrue: [^1].
  903.     self error: 'factorial invalid for: ' , self printString! !'From Smalltalk-80, version 2, of April 1, 1983 on 29 March 1987 at 5:08:59 pm'!
  904.  
  905.  
  906.  
  907. !Integer methodsFor: 'factorization and divisibility'!
  908.  
  909. factorial4
  910.     "Answer the factorial of the receiver.  For example,
  911.      6 factorial == 6*5*4*3*2*1. Signal an error if the receiver
  912.      is less than 0. Use explicitly parallel lazy evaluation."
  913.  
  914.     self > 0
  915.         ifTrue: [^self * [(self - 1) factorial] lazyValue].
  916.     self = 0
  917.         ifTrue: [^1].
  918.     self error: 'factorial invalid for: ' , self printString! !Object subclass: #BinaryIntegration
  919.     instanceVariableNames: 'function '
  920.     classVariableNames: ''
  921.     poolDictionaries: ''
  922.     category: 'Parallel-algorithms'!
  923. BinaryIntegration comment:
  924. 'I represent a numerical integration of a function.  I support a
  925. parallel recursive sub-division algorithm, in both a throttled and
  926. free form.
  927. '!
  928.  
  929.  
  930. !BinaryIntegration methodsFor: 'private'!
  931.  
  932. function: aBlock
  933.     "Set the function to be integrated to aBlock."
  934.  
  935.     function _ aBlock! !
  936.  
  937. !BinaryIntegration methodsFor: 'accessing'!
  938.  
  939. areaBetween: left and: right 
  940.     "Answer the calculated area between the two  
  941.      numbers."
  942.  
  943.     ^self
  944.         areaBetween: left
  945.         and: right
  946.         estimate: (self trapeziumBetween: left and: right)
  947.         tolerance: 0.01!
  948.  
  949. areaBetween: left and: right estimate: anEstimate tolerance: aTolerance 
  950.     "Answer the calculated area between the two  
  951.      numbers. Uses a parallel recursive sub-division algorithm."
  952.  
  953.     | mid areaLeft areaRight newEstimate |
  954.     mid _ left + right / 2.
  955.     areaLeft _ [self trapeziumBetween: left and: mid] futureValue.
  956.     areaRight _ [self trapeziumBetween: mid and: right] futureValue.
  957.     newEstimate _ (areaLeft touch) + (areaRight touch).
  958.     (anEstimate - newEstimate) abs < aTolerance
  959.         ifTrue: [^newEstimate]
  960.         ifFalse: [
  961.             ^[self
  962.                 areaBetween: left
  963.                 and: mid
  964.                 estimate: areaLeft
  965.                 tolerance: aTolerance / 2]
  966.              parallelPerform: #+ with:
  967.               [self
  968.                     areaBetween: mid
  969.                     and: right
  970.                     estimate: areaRight
  971.                     tolerance: aTolerance / 2]
  972.             ]!
  973.  
  974. throttledAreaBetween: left and: right 
  975.     "Answer the calculated area between the two  
  976.      numbers. Uses explicit parallellism with throttling."
  977.  
  978.     ^self
  979.         throttledAreaBetween: left
  980.         and: right
  981.         estimate: (self trapeziumBetween: left and: right)
  982.         tolerance: 0.01!
  983.  
  984. throttledAreaBetween: left and: right estimate: anEstimate tolerance: aTolerance 
  985.     "Answer the calculated area between the two  
  986.      numbers. Uses a parallel recursive sub-division algorithm.
  987.      Uses explicit throttling to keep the number of processes to
  988.      a managable size."
  989.  
  990.     | mid areaLeft areaRight newEstimate |
  991.     mid _ left + right / 2.
  992.     areaLeft _ [self trapeziumBetween: left and: mid] throttledFutureValue.
  993.     areaRight _ [self trapeziumBetween: mid and: right] throttledFutureValue.
  994.     newEstimate _ (areaLeft touch) + (areaRight touch).
  995.     (anEstimate - newEstimate) abs < aTolerance
  996.         ifTrue: [^newEstimate]
  997.         ifFalse: [
  998.             ^[self
  999.                 areaBetween: left
  1000.                 and: mid
  1001.                 estimate: areaLeft
  1002.                 tolerance: aTolerance / 2]
  1003.              throttledParallelPerform: #+ with:
  1004.               [self
  1005.                     areaBetween: mid
  1006.                     and: right
  1007.                     estimate: areaRight
  1008.                     tolerance: aTolerance / 2]
  1009.             ]!
  1010.  
  1011. trapeziumBetween: left and: right 
  1012.     "Answer the area for a trapezium between the left 
  1013.      and right indices."
  1014.  
  1015.     ^(right - left) * ((self valueAt: left) + (self valueAt: right)) / 2!
  1016.  
  1017. valueAt: aNumber
  1018.     "Answers a number computed by the function associated with
  1019.      the receiver at aNumber."
  1020.  
  1021.     ^function value: aNumber! !
  1022. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  1023.  
  1024. BinaryIntegration class
  1025.     instanceVariableNames: ''!
  1026.  
  1027.  
  1028. !BinaryIntegration class methodsFor: 'instance creation'!
  1029.  
  1030. function: aBlock
  1031.     "Creates a new instance of a BinaryIntegration, with the
  1032.      function given by aBlock."
  1033.  
  1034.     ^super new function: aBlock! !
  1035.  
  1036. !BinaryIntegration class methodsFor: 'examples'!
  1037.  
  1038. example1
  1039.     "Illustrating the use of BinaryIntegration. Calculates the area under
  1040.      the curve given by the function, using a parallel recursive sub-division
  1041.      algorithm."
  1042.  
  1043.     | integration |
  1044.     integration _ BinaryIntegration function: [:x| (3*x*x*x) + (2*x*x) + 5].
  1045.     Transcript cr; show: (integration areaBetween: 0 and: 5) printString.
  1046.  
  1047.     "BinaryIntegration example1."
  1048.  
  1049.     "The correct answer is given by the following expression:"
  1050.  
  1051.     "Transcript cr; show: (((5 raisedTo: 4) * 3/4)
  1052.                          + ((5 raisedTo: 3) * 2/3)
  1053.                           + (5 * 5) asFloat) printString."!
  1054.  
  1055. example2
  1056.     "Illustrating the use of BinaryIntegration. Calculates the area under
  1057.      the curve given by the function, using a parallel recursive sub-division
  1058.      algorithm.  This version uses throttling to control the number of processes
  1059.      created at a time."
  1060.  
  1061.     | integration |
  1062.     integration _ BinaryIntegration function: [:x| (3.0*x*x*x) + (2.0*x*x) + 5.0].
  1063.     Transcript cr; show: (integration throttledAreaBetween: 0 and: 5) printString.
  1064.  
  1065.     "BinaryIntegration example2."! !
  1066.  
  1067. Object subclass: #TwoDimMatrix
  1068.     instanceVariableNames: 'matrix '
  1069.     classVariableNames: ''
  1070.     poolDictionaries: ''
  1071.     category: 'Parallel-algorithms'!
  1072. TwoDimMatrix comment:
  1073. 'I represent the class of two-dimensional arrays (matrices).  My
  1074. internal representation is an array of arrays.  I support various
  1075. operations in both serial and explicitly parallel form.
  1076. '!
  1077.  
  1078.  
  1079. !TwoDimMatrix methodsFor: 'private'!
  1080.  
  1081. errorBadDims
  1082.     ^self error: 'matrices must have compatible dimensions'!
  1083.  
  1084. errorBadSize
  1085.     ^self error: 'array is wrong size'!
  1086.  
  1087. errorNotSame
  1088.     ^self error: 'matrices must be the same size'!
  1089.  
  1090. errorNotSquare
  1091.     ^self error: 'matrix must be square'!
  1092.  
  1093. rows: rows columns: columns 
  1094.     "Sets the number of rows and columns in the matrix."
  1095.  
  1096.     matrix _ Array new: columns.
  1097.     1 to: columns do: [:cols | matrix at: cols put: (Array new: rows)]! !
  1098.  
  1099. !TwoDimMatrix methodsFor: 'printing'!
  1100.  
  1101. printOn: aStream
  1102.  
  1103.     matrix printOn: aStream! !
  1104.  
  1105. !TwoDimMatrix methodsFor: 'testing'!
  1106.  
  1107. = aTwoDimMatrix
  1108.     "Answer whether the receiver contains the same elements
  1109.      as aTwoDimMatrix."
  1110.  
  1111.     | cols |
  1112.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^false].
  1113.     1 to: (self columns) do: [:cols |
  1114.         ((self column: cols) = (aTwoDimMatrix column: cols)) ifFalse: [^false].
  1115.     ].
  1116.     ^true!
  1117.  
  1118. isCompatibleWith: aTwoDimMatrix
  1119.     "Answer whether the receiver has dimensions such that
  1120.      it can be multiplied by aTwoDimMatrix."
  1121.  
  1122.     ^(self columns = aTwoDimMatrix rows)!
  1123.  
  1124. isSquare
  1125.     "Answer whether the receiver is a square matrix."
  1126.  
  1127.     ^self rows = self columns!
  1128.  
  1129. isZero
  1130.     "Answer whether the receiver contains all zeros."
  1131.  
  1132.     ^self = (TwoDimMatrix rows: self rows columns: self columns) zero!
  1133.  
  1134. sameSizeAs: aMatrix
  1135.     "Answer whether the receiver has the same
  1136.      dimensions as aMatrix."
  1137.  
  1138.     ^((self rows = aMatrix rows) & (self columns = aMatrix columns))! !
  1139.  
  1140. !TwoDimMatrix methodsFor: 'parallel operations'!
  1141.  
  1142. lazyParallelAdd: aTwoDimMatrix
  1143.     "Answer a new TwoDimMatrix which contains futures to the sum of
  1144.      the receiver and aTwoDimMatrix.  Only calculates a value for an
  1145.      element when it is actually required.  Creates an error message
  1146.      if the receiver and aTwoDimMatrix are not the same size."
  1147.  
  1148.     | newMatrix |
  1149.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1150.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1151.     1 to: (self columns) do: [:cols | 
  1152.         1 to: (self rows) do: [:rows |
  1153.             newMatrix at: (cols@rows) put:
  1154.                 [(self at: (cols@rows)) + (aTwoDimMatrix at: (cols@rows))] lazyValue
  1155.     ]].
  1156.     ^newMatrix!
  1157.  
  1158. lazyParallelMultiply: aTwoDimMatrix
  1159.     "Answers with a new matrix containing lazys to the product
  1160.      of the receiver and aTwoDimMatrix. Only evaluates an
  1161.      element of the matrix when it is needed.  Creates an error message
  1162.      if the dimensions are not compatible."
  1163.  
  1164.     | newMatrix |
  1165.     (self isCompatibleWith: aTwoDimMatrix) ifFalse: [^self errorBadDims].
  1166.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (aTwoDimMatrix columns).
  1167.     1 to: (self rows) do: [:r |
  1168.         1 to: (aTwoDimMatrix columns) do: [:c |
  1169.             newMatrix at: (c@r) put:
  1170.                 ([:x :y | (self row: y) fastDotProduct:
  1171.                     (aTwoDimMatrix column: x)] lazyValue: c value: r).
  1172.     ]].
  1173.     ^newMatrix!
  1174.  
  1175. lazyParallelSubtract: aTwoDimMatrix
  1176.     "Answer a new TwoDimMatrix which contains futures to the difference
  1177.      between the receiver and aTwoDimMatrix.  Only calculates a value for an
  1178.      element when it is actually required.  Creates an error message
  1179.      if the receiver and aTwoDimMatrix are not the same size."
  1180.  
  1181.     | newMatrix |
  1182.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1183.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1184.     1 to: (self columns) do: [:cols | 
  1185.         1 to: (self rows) do: [:rows |
  1186.             newMatrix at: (cols@rows) put:
  1187.                 [(self at: (cols@rows)) - (aTwoDimMatrix at: (cols@rows))] lazyValue
  1188.     ]].
  1189.     ^newMatrix!
  1190.  
  1191. parallelAdd: aTwoDimMatrix
  1192.     "Answer a new TwoDimMatrix which contains futures to the sum of
  1193.      the receiver and aTwoDimMatrix.  Creates an error message
  1194.      if the receiver and aTwoDimMatrix are not the same size."
  1195.  
  1196.     | newMatrix |
  1197.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1198.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1199.     1 to: (self columns) do: [:cols | 
  1200.         1 to: (self rows) do: [:rows |
  1201.             newMatrix at: (cols@rows) put:
  1202.                 [(self at: (cols@rows)) + (aTwoDimMatrix at: (cols@rows))] futureValue
  1203.     ]].
  1204.     ^newMatrix!
  1205.  
  1206. parallelMultiply: aTwoDimMatrix
  1207.     "Answers with a new matrix containing futures to the product
  1208.      of the receiver and aTwoDimMatrix.  Always evaluates every
  1209.      element of the matrix.  Creates an error message if the
  1210.      dimensions are not compatible."
  1211.  
  1212.     | newMatrix |
  1213.     (self isCompatibleWith: aTwoDimMatrix) ifFalse: [^self errorBadDims].
  1214.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (aTwoDimMatrix columns).
  1215.     1 to: (self rows) do: [:r |
  1216.         1 to: (aTwoDimMatrix columns) do: [:c |
  1217.             newMatrix at: (c@r) put:
  1218.              ([:x :y | (self row: y) fastDotProduct:
  1219.                 (aTwoDimMatrix column: x)] futureValue: c value: r)
  1220.     ]].
  1221.     ^newMatrix!
  1222.  
  1223. parallelSubtract: aTwoDimMatrix
  1224.     "Answer a new TwoDimMatrix which contains futures to the difference
  1225.      between the receiver and aTwoDimMatrix.  Creates an error message
  1226.      if the receiver and aTwoDimMatrix are not the same size."
  1227.  
  1228.     | newMatrix |
  1229.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1230.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1231.     1 to: (self columns) do: [:cols | 
  1232.         1 to: (self rows) do: [:rows |
  1233.             newMatrix at: (cols@rows) put:
  1234.                 [(self at: (cols@rows)) - (aTwoDimMatrix at: (cols@rows))] futureValue
  1235.     ]].
  1236.     ^newMatrix! !
  1237.  
  1238. !TwoDimMatrix methodsFor: 'filling'!
  1239.  
  1240. identity
  1241.     "Fill the receiver with all zeros, except for the
  1242.      leading diagonal, which contains ones."
  1243.  
  1244.     self isSquare ifFalse: [^self errorNotSquare].
  1245.     self zero.
  1246.     1 to: (self columns) do: [:count | self at: (count@count) put: 1]!
  1247.  
  1248. random
  1249.     "Fill the receiver with random numbers."
  1250.  
  1251.     | rand |
  1252.     rand _ Random new.
  1253.     1 to: (self columns) do: [:cols |
  1254.         1 to: (self rows) do: [:rows |
  1255.             self at: cols@rows put: rand next]]!
  1256.  
  1257. zero
  1258.     "Set all the elements of the receiver to zero."
  1259.  
  1260.     1 to: (self columns) do: [:cols |
  1261.         1 to: (self rows) do: [:rows |
  1262.             self at: cols@rows put: 0]]! !
  1263.  
  1264. !TwoDimMatrix methodsFor: 'mathematical operations'!
  1265.  
  1266. * aTwoDimMatrix
  1267.     "Answers with a new matrix representing the product
  1268.      of the receiver and aTwoDimMatrix.  Creates an error
  1269.      message if the dimensions are not compatible."
  1270.  
  1271.     | newMatrix |
  1272.     (self isCompatibleWith: aTwoDimMatrix) ifFalse: [^self errorBadDims].
  1273.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (aTwoDimMatrix columns).
  1274.     1 to: (self rows) do: [:r |
  1275.         1 to: (aTwoDimMatrix columns) do: [:c |
  1276.             newMatrix at: (c@r) put:
  1277.                 ((self row: r) fastDotProduct: (aTwoDimMatrix column: c)).
  1278.     ]].
  1279.     ^newMatrix!
  1280.  
  1281. + aTwoDimMatrix
  1282.     "Answer a new TwoDimMatrix which is the sum of
  1283.      the receiver and aTwoDimMatrix.  Create an error message
  1284.      if the receiver and aTwoDimMatrix are not the same size."
  1285.  
  1286.     | newMatrix |
  1287.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1288.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1289.     1 to: (self columns) do: [:cols | 
  1290.         1 to: (self rows) do: [:rows |
  1291.             newMatrix at: (cols@rows) put:
  1292.                 ((self at: (cols@rows)) + (aTwoDimMatrix at: (cols@rows)))
  1293.     ]].
  1294.     ^newMatrix!
  1295.  
  1296. - aTwoDimMatrix
  1297.     "Answer a new TwoDimMatrix which is the difference of
  1298.      the receiver and aTwoDimMatrix.  Create an error message
  1299.      if the receiver and aTwoDimMatrix are not the same size."
  1300.  
  1301.     | newMatrix |
  1302.     (self sameSizeAs: aTwoDimMatrix) ifFalse: [^self errorNotSame].
  1303.     newMatrix _ TwoDimMatrix rows: (self rows) columns: (self columns).
  1304.     1 to: (self columns) do: [:cols | 
  1305.         1 to: (self rows) do: [:rows |
  1306.             newMatrix at: (cols@rows) put:
  1307.                 ((self at: (cols@rows)) - (aTwoDimMatrix at: (cols@rows)))
  1308.     ]].
  1309.     ^newMatrix! !
  1310.  
  1311. !TwoDimMatrix methodsFor: 'accessing'!
  1312.  
  1313. at: aPoint
  1314.     "Answer the value contained in the matrix corresponding to
  1315.      aPoint."
  1316.  
  1317.     | column |
  1318.     column _ matrix at: aPoint x.
  1319.     ^column at: aPoint y!
  1320.  
  1321. at: aPoint put: aValue
  1322.     "Set the value in the matrix corresponding to aPoint."
  1323.  
  1324.     | column |
  1325.     column _ matrix at: aPoint x.
  1326.     column at: aPoint y put: aValue!
  1327.  
  1328. column: aNumber
  1329.     "Answer an array corresponding to the column given
  1330.      by aNumber."
  1331.  
  1332.     ^matrix at: aNumber!
  1333.  
  1334. column: aNumber from: anArray
  1335.     "Set the column in the receiver corresponding to aNumber
  1336.      to the values from anArray."
  1337.  
  1338.     (self column: aNumber) size = (anArray size) ifFalse: [^self errorBadSize].
  1339.     1 to: anArray size do: [:index |
  1340.         self at: aNumber@index put: (anArray at: index)].!
  1341.  
  1342. columns
  1343.     "Answer the number of columns in the receiver."
  1344.  
  1345.     (matrix size = 0) ifTrue: [^0].
  1346.     ^matrix size!
  1347.  
  1348. row: aNumber
  1349.     "Answer an array corresponding to the row given
  1350.      by aNumber."
  1351.  
  1352.     | temp |
  1353.     temp _ Array new: (self columns).
  1354.     1 to: (self columns) do: [:col | temp at: col put: (self at: (col@aNumber))].
  1355.     ^temp!
  1356.  
  1357. row: aNumber from: anArray
  1358.     "Set the row in the receiver corresponding to aNumber
  1359.      to the values from anArray."
  1360.  
  1361.     (self row: aNumber) size = (anArray size) ifFalse: [^self errorBadSize].
  1362.     1 to: anArray size do: [:index |
  1363.         self at: index@aNumber put: (anArray at: index)].!
  1364.  
  1365. rows
  1366.     "Answer the number of rows in the receiver."
  1367.  
  1368.     (matrix size = 0) ifTrue: [^0].
  1369.     ^matrix first size! !
  1370. "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "!
  1371.  
  1372. TwoDimMatrix class
  1373.     instanceVariableNames: ''!
  1374.  
  1375.  
  1376. !TwoDimMatrix class methodsFor: 'examples'!
  1377.  
  1378. example1
  1379.     "Illustrates the use of matrix addition."
  1380.  
  1381.     | a b |
  1382.     a _ TwoDimMatrix rows: 2 columns: 2.
  1383.     a row: 1 from: #(1 2).
  1384.     a row: 2 from: #(3 4).
  1385.     b _ TwoDimMatrix rows: 2 columns: 2.
  1386.     b column: 1 from: #(5 6).
  1387.     b column: 2 from: #(7 8).
  1388.     Transcript cr; show: (a + b) printString.
  1389.  
  1390.     "TwoDimMatrix example1."!
  1391.  
  1392. example2
  1393.     "Illustrates the use of matrix subtraction."
  1394.  
  1395.     | a b |
  1396.     a _ TwoDimMatrix rows: 2 columns: 2.
  1397.     a row: 1 from: #(1 2).
  1398.     a row: 2 from: #(3 4).
  1399.     b _ TwoDimMatrix rows: 2 columns: 2.
  1400.     b column: 1 from: #(5 6).
  1401.     b column: 2 from: #(7 8).
  1402.     Transcript cr; show: (b - a) printString.
  1403.  
  1404.     "TwoDimMatrix example2."!
  1405.  
  1406. example3
  1407.     "Illustrates the use of matrix operations.  Note that
  1408.      matrices are *not* commutitive under multiplication,
  1409.      so that a*b <> b*a."
  1410.  
  1411.     | a b |
  1412.     a _ TwoDimMatrix rows: 2 columns: 2.
  1413.     a row: 1 from: #(1 2).
  1414.     a row: 2 from: #(3 4).
  1415.     b _ TwoDimMatrix rows: 2 columns: 2.
  1416.     b column: 1 from: #(5 6).
  1417.     b column: 2 from: #(7 8).
  1418.     Transcript cr; show: ((a+b)*(a-b)) printString.
  1419.     Transcript cr; show: ((a*a) - (b*b)) printString.
  1420.     Transcript cr; show: (((a+b)*(a-b)) = ((a*a)-(b*b))) printString.
  1421.  
  1422.     "TwoDimMatrix example3."!
  1423.  
  1424. example4
  1425.     "Multiplies together two large matrices."
  1426.  
  1427.     | a1 a2 |
  1428.     a1 _ (TwoDimMatrix rows: 12 columns: 10) random.
  1429.     a2 _ (TwoDimMatrix rows: 10 columns: 11) random.
  1430.     Transcript cr; show: (Time millisecondsToRun: [a1 * a2]) printString.
  1431.  
  1432.     "TwoDimMatrix example4."!
  1433.  
  1434. example5
  1435.     "Illustrates a parallel matrix addition using futures.  The resulting
  1436.      matrix is always fully evaluated, even if only one element is
  1437.      required."
  1438.  
  1439.     | a1 a2 |
  1440.     a1 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1441.     a2 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1442.     Transcript cr; show: (Time millisecondsToRun: [(a1 parallelAdd: a2) at: 2@3]) printString
  1443.  
  1444.     "TwoDimMatrix example5."!
  1445.  
  1446. example6
  1447.     "Illustrates a parallel matrix addition using lazy evaluation.  The resulting
  1448.      matrix is only evaluated when an element is actually required."
  1449.  
  1450.     | a1 a2 |
  1451.     a1 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1452.     a2 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1453.     Transcript cr; show: (Time millisecondsToRun: [(a1 lazyParallelAdd: a2) at: 2@3]) printString
  1454.  
  1455.     "TwoDimMatrix example6."!
  1456.  
  1457. example7
  1458.     "Illustrates the use of a Lazy-evaluated matrix multiplication.
  1459.      Only the value actually requested is calculated."
  1460.  
  1461.     | a1 a2 |
  1462.     a1 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1463.     a2 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1464.     Transcript cr; show: ((a1 lazyParallelMultiply: a2) at: 7@5) printString.
  1465.  
  1466.     "TwoDimMatrix example7."!
  1467.  
  1468. example8
  1469.     "Illustrates the use of a Lazy-evaluated matrix multiplication.
  1470.      Only the value actually requested is calculated.  Compare with
  1471.      example9."
  1472.  
  1473.     | a1 a2 |
  1474.     a1 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1475.     a2 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1476.     Transcript cr; show: (Time millisecondsToRun: [
  1477.         ((a1 lazyParallelMultiply: a2) at: 7@5) touch]) printString.
  1478.  
  1479.     "TwoDimMatrix example8."!
  1480.  
  1481. example9
  1482.     "Illustrates the use of a fully-evaluated parallel matrix multiplication.
  1483.      All values are calculated.  Compare with example8."
  1484.  
  1485.     | a1 a2 |
  1486.     a1 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1487.     a2 _ (TwoDimMatrix rows: 10 columns: 10) random.
  1488.     Transcript cr; show: (Time millisecondsToRun: [
  1489.         ((a1 parallelMultiply: a2) at: 7@5) touch]) printString.
  1490.  
  1491.     "TwoDimMatrix example9."! !
  1492.  
  1493. !TwoDimMatrix class methodsFor: 'instance creation'!
  1494.  
  1495. identity: aNumber
  1496.     "Answer a new matrix which is square, and is all zero
  1497.      except for the leading diagonal, which is 1."
  1498.  
  1499.     ^(self new rows: aNumber columns: aNumber) identity!
  1500.  
  1501. rows: rows columns: columns 
  1502.     "Create a new instance of the receiver, with 
  1503.      the number of rows and columns given."
  1504.  
  1505.     ^super new rows: rows columns: columns!
  1506.  
  1507. zero: aNumber
  1508.     "Answer a new matrix which is square, and is all zero."
  1509.  
  1510.     ^(self new rows: aNumber columns: aNumber) zero! !'From Smalltalk-80, version 2, of April 1, 1983 on 9 April 1987 at 9:20:16 pm'!
  1511.  
  1512.  
  1513.  
  1514. !Number methodsFor: 'parallel intervals'!
  1515.  
  1516. to: stop asyncParallelDo: aBlock 
  1517.     "Create an Interval from the receiver up to the argument, stop,
  1518.     incrementing by 1.  For each element of the interval, evaluate the
  1519.     block, aBlock, in parallel.  Blocks are start immediately, and
  1520.     continue asynchronously."
  1521.  
  1522.     | nextValue aPE |
  1523.     nextValue _ self.
  1524.     aPE _ ParallelEvaluation new.
  1525.     [nextValue <= stop]
  1526.         whileTrue: 
  1527.             [aPE add: aBlock value: nextValue.
  1528.              nextValue _ nextValue + 1]!
  1529.  
  1530. to: stop by: step asyncParallelDo: aBlock 
  1531.     "Create an Interval from the receiver up to the argument, stop,
  1532.     incrementing by step.  For each element of the interval, evaluate the
  1533.     block, aBlock, in parallel.  Blocks are started immediately, and
  1534.     continue asynchronously."
  1535.  
  1536.     | nextValue aPE |
  1537.     nextValue _ self.
  1538.     aPE _ ParallelEvaluation new.
  1539.     step < 0
  1540.         ifTrue: [[stop <= nextValue]
  1541.                 whileTrue: 
  1542.                     [aPE add: aBlock value: nextValue.
  1543.                     nextValue _ nextValue + step]]
  1544.         ifFalse: [[stop >= nextValue]
  1545.                 whileTrue: 
  1546.                     [aPE add: aBlock value: nextValue.
  1547.                     nextValue _ nextValue + step]]!
  1548.  
  1549. to: stop by: step parallelDo: aBlock 
  1550.     "Create an Interval from the receiver up to the argument, stop,
  1551.     incrementing by step.  For each element of the interval, evaluate the
  1552.     block, aBlock, in parallel.  Ensure that all blocks are completed before
  1553.     continuing."
  1554.  
  1555.     | nextValue aPE |
  1556.     nextValue _ self.
  1557.     aPE _ ParallelEvaluation new.
  1558.     step < 0
  1559.         ifTrue: [[stop <= nextValue]
  1560.                 whileTrue: 
  1561.                     [aPE add: aBlock value: nextValue.
  1562.                     nextValue _ nextValue + step]]
  1563.         ifFalse: [[stop >= nextValue]
  1564.                 whileTrue: 
  1565.                     [aPE add: aBlock value: nextValue.
  1566.                     nextValue _ nextValue + step]].
  1567.     aPE do        "ensure completion."!
  1568.  
  1569. to: stop parallelDo: aBlock 
  1570.     "Create an Interval from the receiver up to the argument, stop,
  1571.     incrementing by 1.  For each element of the interval, evaluate the
  1572.     block, aBlock, in parallel.  Ensure completion of all blocks before
  1573.     continuing."
  1574.  
  1575.     | nextValue aPE |
  1576.     nextValue _ self.
  1577.     aPE _ ParallelEvaluation new.
  1578.     [nextValue <= stop]
  1579.         whileTrue: 
  1580.             [aPE add: aBlock value: nextValue.
  1581.              nextValue _ nextValue + 1].
  1582.     aPE do        "Ensure completion."! !
  1583. Transcript cr; show: 'Initializing Future'.
  1584. Future initialize.
  1585. Transcript cr; show: 'Initializing Lazy'.
  1586. Lazy initialize. !
  1587.  
  1588.